package com.enation.app.javashop.core.shop.service.impl;

import com.enation.app.javashop.core.shop.model.dos.ShopGisDO;
import com.enation.app.javashop.core.shop.model.dto.ShopGisDTO;
import com.enation.app.javashop.core.shop.model.vo.ShopGisVO;
import com.enation.app.javashop.core.shop.service.ShopGisManager;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.util.BeanUtil;
import com.enation.app.javashop.framework.util.DateUtil;
import com.enation.app.javashop.framework.util.ReflectionUtil;
import net.sf.json.JSONArray;
import net.sf.json.JsonConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @Author 王志杨
 * @Date 2020/8/26 14:54
 * @Descroption 店铺服务范围业务实现类
 * @Since
 * @Version
 */
@Service
public class ShopGisManagerImpl implements ShopGisManager {

    private static final Integer SUCCESS_CODE = 200;
    private static final Integer ERROR_CODE = 222;
    @Autowired
    @Qualifier("memberDaoSupport")
    private DaoSupport shopDaoSupport;

    private final Log logger = LogFactory.getLog(this.getClass());

    /**
     * 添加店铺服务范围
     * @param shopGisDTO 店铺服务范围DTO
     */
    @Override
    public void insertShopGis(ShopGisDTO shopGisDTO) {
        try {
            //参数校验
            Assert.notNull(shopGisDTO,"请求对象不得为空");
            Integer polygonId = shopGisDTO.getPolygonId();
            Assert.isTrue(polygonId != null && polygonId > 0, "polygonId不得为空");
            String createName = shopGisDTO.getCreateName();
            Assert.hasText(createName,"绘制人不得为空");
            Integer shopId = shopGisDTO.getShopId();
            Assert.isTrue(shopId != null && shopId >= 0, "shop_id不得为空且必须大于0");
            List<List<Double>> polygons = shopGisDTO.getPolygonCoords();
            Assert.notEmpty(polygons,"范围节点坐标的集合不得为空");
            int hasData = this.shopDaoSupport.queryForInt("select count(shop_id) from es_shop_gis where shop_id=?", shopId);
            //List转JSON
            JSONArray jsonArray = JSONArray.fromObject(polygons);
            ////遍历List<List<Double>>类型,拼接Polygon参数
            String polygon = concatMultiPolygon(polygons);
            //属性赋值
            ShopGisDO shopGisDO = new ShopGisDO();
            BeanUtil.copyProperties(shopGisDTO, shopGisDO);
            shopGisDO.setCreateTime(DateUtil.getDateline());
            shopGisDO.setPolygonJson(jsonArray.toString());
            shopGisDO.setPolygonCoords(polygon);
            //添加时数据库中不需要中心点和gisId
            Map map = ReflectionUtil.po2MapIncludeNull(shopGisDO);
            map.remove("gis_id");
            map.remove("center_point_str");
            Object[] keys = map.keySet().toArray();
            //params要在遍历中按照key获取，否则无法保证顺序
            Object[] params = new Object[keys.length];
            //动态生成sql
            StringBuilder sqlKeys = new StringBuilder();
            StringBuilder sqlValues = new StringBuilder(" VALUES (");
            for (int i = 0; i < keys.length; i++) {
                sqlKeys.append(keys[i]);
                if ("polygon_coords".equals(keys[i])) {
                    sqlValues.append("ST_GeomFromText(?)");
                } else {
                    sqlValues.append("?");
                }
                if(i < keys.length - 1){
                    sqlKeys.append(",");
                    sqlValues.append(",");
                }
                if (map.get(keys[i]) == null) {
                    params[i] = null;
                } else {
                    params[i] = map.get(keys[i]).toString();
                }
            }
            sqlValues.append(")");
            StringBuilder sqlBuilder = new StringBuilder("INSERT INTO es_shop_gis(").append(sqlKeys).append(") ").append(sqlValues);
            //执行sql
            this.shopDaoSupport.execute(sqlBuilder.toString(), params);
        } catch (Exception e) {
            logger.error("店铺服务范围添加失败", e);
            throw new RuntimeException("店铺服务范围添加失败" + e.getMessage());
        }
//        String sql;
//        if(hasData > 0){
//            sql = "update es_shop_gis set polygon_json=?,multi_polygon=ST_GeomFromText(?),update_name=?,update_time=?) where shop_id=?";
//            Object[] params = {jsonArray.toString(), polygon, createName, now, shopId};
//            this.shopDaoSupport.execute(sql, params);
//        }else{
//
//            sql = "INSERT INTO es_shop_gis(shop_id,polygon_id,polygon_coords,polygon_json,create_name,create_time,update_name,update_time) VALUES (?,?,ST_GeomFromText(?),?,?,?,?)";
//            Object[] params = {shopId ,jsonArray.toString(), polygon, createName, now, createName, now};
//            //动态填充参数，并执行sql
//            this.shopDaoSupport.execute(sql, params);
//        }
    }

    /**
     * 通过shop_id获取店铺服务范围节点坐标集合
     * @param shopId
     * @return List<ShopGisDTO>
     */
    @Override
    public ShopGisVO getShopGisByShopId(Integer shopId) {
        //参数校验
        Assert.isTrue(shopId != null && shopId >= 0, "shop_id不得为空且必须大于0");
        String sql = "select gis_id,shop_id,polygon_json,create_name,create_time,update_name,update_time from es_shop_gis where shop_id=?";
        //查询多多边形坐标集合
        ShopGisDO shopGisDO = this.shopDaoSupport.queryForObject(sql, ShopGisDO.class, shopId);
        //将数据库中获取的多多边形坐标JSON转换为List<List<Double>>类型
        List<List<Double>> polygons = turnJsonToList(shopGisDO.getPolygonJson());
        //DO转VO
        ShopGisVO shopGisVO = new ShopGisVO();
        BeanUtil.copyProperties(shopGisDO,shopGisVO);
        shopGisVO.setPolygons(polygons);
        return shopGisVO;
    }

    /**
     * 检测指定收货点的坐标是否在shop_id店铺的配送范围
     * @param coord
     * @param shopId
     * @return 200 在范围内，444不在配送范围内
     */
    @Override
    public Integer checkPointWithinMultiPolygon(Double[] coord, Integer shopId) {
        //参数校验
        Assert.notEmpty(coord,"经纬坐标不得为空！");
        Assert.isTrue(coord.length == 2,"获取经纬坐标数量有误");
        Assert.isTrue(shopId != null && shopId >= 0, "shop_id不得为空且必须大于0");
        String sql = "select MBRWithin(ST_GeomFromText('POINT("+ coord[0] +" "+ coord[1] +")'),(select multi_polygon from es_shop_gis where shop_id=?));";
        Integer result = shopDaoSupport.queryForInt(sql, shopId);
        return result == 1 ? SUCCESS_CODE : ERROR_CODE;
    }

    /**
     * 判断买家要求配送位置的经纬坐标属于哪些自提点的配送范围内
     * @param coord 买家要求配送位置的经纬坐标
     * @return 属于配送范围的集合
     */
    @Override
    public List<ShopGisVO> checkPointBelongMultiPolygon(Double[] coord) {
        //参数校验
        Assert.notEmpty(coord,"经纬坐标不得为空！");
        Assert.isTrue(coord.length == 2, "获取经纬坐标数量有误");
        String sql = "select gis_id,shop_id,polygon_json from es_shop_gis s " +
                "WHERE ST_Contains(s.multi_polygon,ST_GeomFromText('POINT("+ coord[0] + " " + coord[1] + ")'))";
        List<ShopGisDO> shopGisDOs = shopDaoSupport.queryForList(sql, ShopGisDO.class);
        Assert.notEmpty(shopGisDOs, "该位置暂无配送服务");
        // List<ShopGisDO>转换为List<ShopGisVO> && JSON-->List<List<Double>>
        return turnShopGisDOsToShopGisVOs(shopGisDOs);
    }

    /**
     * 根据市级地区ID查询范围内所有自提点的服务范围的集合
     * @param shop_city_id 市级地区ID
     * @return 属所有自提点的服务范围的集合
     */
    @Override
    public List<ShopGisVO> getMultiPolygonByAreaId(Integer shop_city_id) {
        Assert.isTrue(shop_city_id != null && shop_city_id >= 0, "shop_city_id不得为空且必须大于0");
        String sql = "select gis_id,shop_id,polygon_json from es_shop_gis " +
                "where shop_id in (select shop_id from es_shop_detail where shop_city_id = ?)";
        List<ShopGisDO> shopGisDOs = shopDaoSupport.queryForList(sql, ShopGisDO.class, shop_city_id);
        Assert.notEmpty(shopGisDOs, "该位置暂无配送服务");
        // List<ShopGisDO>转换为List<ShopGisVO> && JSON-->List<List<Double>>
        return turnShopGisDOsToShopGisVOs(shopGisDOs);
    }

    //-------------------------------------方法抽取-------------------------------------------
    /**
     * List<ShopGisDO>转换为List<ShopGisVO> && JSON-->List<List<Double>>
     * @param shopGisDOs
     * @return
     */
    private List<ShopGisVO> turnShopGisDOsToShopGisVOs(List<ShopGisDO> shopGisDOs) {
        List<ShopGisVO> shopGisVOs = new ArrayList<>();
        for (ShopGisDO shopGisDO: shopGisDOs) {
            //将数据库中获取的多多边形坐标JSON转换为List<List<Double>>类型
            List<List<Double>> multiPolygon = turnJsonToList(shopGisDO.getPolygonJson());
            //DO转VO
            ShopGisVO shopGisVO = new ShopGisVO();
            BeanUtil.copyProperties(shopGisDO, shopGisVO);
            shopGisVO.setPolygons(multiPolygon);
            shopGisVOs.add(shopGisVO);
        }
        return shopGisVOs;
    }

    /**
     * 传入JSON多多边型集合，转换为List<List<Double>>
     * @param polygonJson
     * @return List<List<Double>>
     */
    private List<List<Double>> turnJsonToList(String polygonJson) {
        JSONArray jsonArray = JSONArray.fromObject(polygonJson);
        List<List<Double>> polygons = JSONArray.toList(jsonArray, List.class, new JsonConfig());
        return polygons;
    }


    /**
     * 传入List<List<Double>>类型多多边型集合，拼接为MultiPolygon类型的sql
     * @param polygons
     * @return
     */
    private String concatMultiPolygon(List<List<Double>> polygons) {
        StringBuilder multiPolygon = new StringBuilder("Polygon((");
        for (List<Double> polygon: polygons) {
            multiPolygon.append(polygon.get(0)).append(" ").append(polygon.get(1)).append(",");
        }
        multiPolygon = new StringBuilder(multiPolygon.substring(0, multiPolygon.lastIndexOf(","))).append("))");
        return multiPolygon.toString();
    }
}
